grammar Pin;  //定义Hello语法


program : (function|defglobal|statement|declareStruct|CHINESE_SYMBOL)* // 定义函数  //这里必须要+ 否则访问到第一个函数定义就退出，导致之前一直无法监听到所有的函数，只能监听到第一个
    ;
//这里必须要留着statement,发生错误后，可进一步确定错误的位置。还有就是不能使用unknown，之前使用unknown替换statement，可以避免野语句，但是函数中间存在错误时，定位不了。

//execfun : statement+ ; //当后面执行函数体时，直接调用这个即可。

//mainFun : 'hanshu' 'hs_rukou' '(' ')' block ; //这样会导致错误，如果想要从hs_rukou还是执行，直接在代码中控制就行。

//全局区域，所有全局变量都必须定义在下面，不能随意乱放

defglobal : GLOBAL '{' globalstate* '}' ';'?;
GLOBAL: 'quanju_dingyi' | 'global' ;

globalstate: defvar
	|defstvar
	| assign
	|declareStruct
	;



block :'{' statement* '}';

statement : defvar 	 	       //定义变量
	| defstvar
	| assign 				//赋值
	| hs_print 					//打印函数
	//| callMain
	| callFun			      //调用函数
	| block			        //语句块	
	| retCode				//return 语句 
	| if					// if 表达式
	| for					//for 循环表达式
	| break
	| continue
	| signalState
	| pass
	;

signalState: expr ';' ; //单个语句，啥也不要

pass:'pass;';

//定义变量。不允许出现定义变量，但是不赋初始值的情况

//NING_SPACE : NING ' ';
//TYPE_ID_SPACE : TYPE_ID ' ';

defvar: //NING_SPACE assign
	 TYPE_ID (assign | (VARNAME (',' VARNAME)* ';'))  //定义加赋值

	//| TYPE_ID_SPACE pinvar //只定义不赋值。
	;

//defonevar: TYPE_ID VARNAME;

//结构体申明
JIEGOU_SPACE: JIEGOU_KEY ' ';
declareStruct: JIEGOU_SPACE VARNAME struct_body ';'? ; //申明一种结构
JIEGOU_KEY: 'jiegou' | 'struct';

defstvar : VARNAME onest (',' VARNAME ? onest)* ';' ; //结构体变量的定义


onest: assignStOne  //定义加赋值。
	| VARNAME								//只定义，不赋值
	;

//定义元组
//变量赋值
assign: assginNoEnd ';' ;

assginNoEnd: assignOne (',' assignOne)* ;

assignOne:  //pinvar AUTO_ADD_SUB #assignAutoAdd //a++ a-- 这种。
	   pinvar assignOp rightvar  #assignVar//表达法方式的赋值
	|  assignStOne #assignStructVar //结构体赋值 {} 方式赋值

	//| assignListOne #assignListVar //列表赋值 [] 方式赋值 作废，不能对list[1] = [] 情况赋值
	//| assignMapOne #assignMapVar //字典以{}方式赋值 作废 不能对 不能map[1] = [] {} 情况赋值
	//| accesslist '=' list #assignListVar  //  list map 均不是表达式，需要单独提取出来赋值。列表赋值 [] 方式赋值
	//| accessmap '=' map #assignMapVar //字典以{}方式赋值 代码冗余太多，直接合并到第一条
	;

AUTO_ADD_SUB:'++'
	|'--'
	;

rightvar : expr
	| list
	| map
	| stRightVar //lb_1 =  JG_INFO {1,2,3} 的方式。
	| EMPTY_VALUE
	//| realCallFun
	;
EMPTY_VALUE : 'kong'; //空对象，只有文件和时间可以设置为该类型。

stRightVar : VARNAME '{' expr (',' expr)* '}'; 

assignStOne: VARNAME '=' (('{' expr (',' expr)* '}') | stFromExpr)
	;

stFromExpr: expr;

//assignListOne: LIST_ID '=' list ;

//assignMapOne: MAP_ID '=' map ;

assignOp : '=' 
	| '/='
	| '*/'
	| '+='
	| '-='
	;




AND : '&&' | 'and' ;
OR : '||' | 'or' ;
NOT : '!' | 'not';
IN : 'in' ;


LOG_REV : '~'; //位取反
LOG_AND : '&'; //并
LOG_OR : '|';  //位或
LOG_XOR : '^'; //位异或



// 新增规则，用于在标识符后面添加分隔符
//exprList : expr (IDENTIFIER_END expr)* ;

// 新增一个规则来匹配标识符后面的空白或操作符，避免标识符粘连
//IDENTIFIER_END : AND | OR | NOT ;

// 新增一个规则来匹配 hs_print 中的格式化部分
//printFormatPart: '%' '(' expr (',' expr)* ')' ;
printFormatPart: '%' ( singleExpr | multiExpr );  // 二选一：单参数或多参数

singleExpr
    : expr            // 单个 expr，不带括号（如 %x）
    ;

multiExpr
    : '(' expr (',' expr)* ')'  // 多个 expr，带括号（如 %(x,y,z)）
    ;

fmtString :format_string  printFormatPart;

hs_print: DA_YIN_KEY '(' fmtString ')' ';' #formatPrintExpr
	| DA_YIN_KEY '(' expr (',' expr)* ')' ';' #printExpr
	| DA_YIN_KEY '<<' expr ('<<' expr)* ';' #outputExpr
	;

DA_YIN_KEY : 'hs_dayin'
	| 'dy'
	| 'dyh'
	| 'print'
	| 'println'
	;

pinAutoAddSub : pinvar AUTO_ADD_SUB;

expr :'(' expr ')' #parenthesesExpr   // 负号，仅在特定上下文出现
	| pinFlag #flagExpr
	| pinAutoAddSub #assignAutoAdd
    | '-' atom #negationExpr
	| LOG_REV revVar #logRevExpr //逻辑取反

	| expr '*' expr 	#multExpr
    | expr '/' expr 	#divExpr
	| fmtString 		#fmtStrExpr //放在%前面，提高优先级，避免干扰。
	| expr '%' expr 	#remainderExpr
    | expr '+' expr 	#addExpr
    | expr '-' expr 	#subExpr

	| expr '<' expr		#lessExpr
	| expr '<=' expr	#lessEqualExpr
	| expr '>' expr		#greaterExpr
	| expr '>=' expr	#greaterEqualExpr

	| expr '==' expr	#equalExpr
	| expr '!=' expr	#unequalExpr

	| expr LOG_AND expr #logAndExpr
	| expr LOG_XOR expr 	#logXorExpr  
	| expr LOG_OR expr 	#logOrExpr  //位运算优先级最低

	| expr NOT IN rightvar #notinExpr
	| expr IN rightvar #inExpr

	| NOT expr	#notExpr
	| expr AND expr #andExpr
	| expr OR expr 	#orExpr

    | INT_VALUE 		#intExpr
    | FLOAT_VALUE 		#floatExpr
	| STRING_VALUE			#strExpr
	| RAW_STRING_VALUE		#rowStrExpr
	| BOOL_VALUE		#boolValueExpr
	| CHAR_VALUE		#charValueExpr
	//| EMPTY_VALUE 		#kongExpr

	| pinvar 			#varExpr
	//| pinvar(.memberFunAccess)+ #multiFunAccessExpr
	| realCallFun		#callFunExpr //函数调用也可做表达式，但只能有一个返回结果，多余结果被丢弃。

;

list : '[' (element (',' element)*)? ']';

element : expr
	|	list
	| stRightVar
	;

map : '{' (mapelement (',' mapelement)*)? '}';

//map的元素必须是键值对。
mapelement: mapkey ':' rightvar;
mapkey: expr ;//map的key只能是整数和字符串。
//mapvalue: rightvar; 直接就是rightvar即可。

// 基本原子元素，用于负号判断的上下文
atom : INT_VALUE
     | FLOAT_VALUE
	 | pinvar
     //| INT32
	 //| INT64
	 //| FLOAT
     ;

	 //只有整数才能取反。
revVar : pinvar//INT32 
	//| INT64
	;

pinvar :VARNAME ('[' listindex ']')* ('.'stMemVar)? ;

/*
	| basevar 
	| structMem   //优先匹配成员访问
	| STRUCT_ID  				//最后单独匹配结构体
	| accesslist			//访问列表，或列表成员
	| accessmap 		//访问字典，或字典的值
	| FILE_ID 				//文件
	| DATE_ID 	 //日期时间

	//| structMemVar
	//| listMapVar //list map 格式是一个的，合并为1个。
	//| VARNAME //通用变量名称，不以前缀区分类型了。
	| var 
	;
*/

//basevar : //INT32 
	 // INT64 	
	 //  FLOAT 	//统一使用double,就是c++中的double
	//   STRING  
	//|   BOOL 	
	//|   CHAR 	 //单个字符，cpp中的char
//	;


//列表访问
//accesslist : LIST_ID ('[' listindex ']')* ('.'stMemVar)?;

listMapVar : VARNAME ('[' listindex ']')* ('.'stMemVar)?;

listindex : expr;


//字典访问
//accessmap : MAP_ID ('[' listindex ']')* ('.'stMemVar)?;



//结构体
structMem : VARNAME '.' stMemVar ;

structMemVar : VARNAME '.' stMemVar ;

stMemVar: VARNAME 
	;

//成员函数访问
memberFunAccess : funobj '.' VARNAME;
funobj :TYPE_ID|PACK_NAME|pinvar ;//FILE_ID | LIST_ID | MAP_ID  | DATE_ID | STRING;

//HANSHU_SPACE: 'hanshu' ' ';
function : HANSHU VARNAME '(' defArgumentList? ')' defFunRet? block ;	//定义函数

HANSHU : 'hanshu' | 'func';
defFunRet :  '(' funretArg (',' funretArg)* ')'
	| '(' ')'
	;

//结构申明
//STRUCT_DESC_ID : 'JG_'STKEY; //结构体声明只能使用大写字母
//STRUCT_DESC_ID_SPACE: STRUCT_DESC_ID ' ';

funretArg : TYPE_ID  
	| VARNAME  //其次匹配结构体赋值
;

//FANHUI_SPACE: FANHUI_KEY ' '; //单独写 return ; return 和; 有个空格，如果开启则会失败。20250412
retCode : FANHUI_KEY rightvar (',' rightvar)* ';' //#retExpr //以调用表达式的方式返回。至少一个返回值。
	| FANHUI_KEY ';' //没有返回值。
	;
FANHUI_KEY : 'fanhui' | 'return' ;

//定义函数定义的参数列表，注意和调用不一样,分开处理方便一些
defArgumentList : defArgument (',' defArgument)* ;


defArgument : TYPE_ID VARNAME
	| HUIDIAO VARNAME //匹配回调函数
	| VARNAME VARNAME //其次匹配结构体赋值
	//| memberFunAccess 		//匹配内部成员函数访问 ，也当做函数
;

HUIDIAO : 'hs';


format_string: STRING_VALUE;

//callMain: FANHUI_SPACE? 'hs_rukou' '(' ('lb' VARNAME) ?')';

callFun : realCallFun  ';' #noRetCallFun //以不关心函数返回值的情况调用函数
	| fun_ret realCallFun 	';' #withRetCallFun //以关心函数返回值的情况调用函数
	| FANHUI_KEY realCallFun  ';' #returnCallFun //以返回函数结果的情况调用函数
	;

realCallFun :
		//| pinvar '(' argumentList? ')' 
		 memberFunAccess '(' argumentList? ')' multiCallFun*  //转调用cpp qt的函数。
		|VARNAME '(' argumentList? ')' multiCallFun*  //普通函数，自定义的函数
		//| CALL_FUN '(' argumentList? ')'   //传递给函数的回调函数
		;
	//| PACK_NAME '.' FUN_NAME '(' argumentList? ')' ';' //包名方式调用函数，比如bao_wj bao_shuxue等
	//| VAR_TYPE '.' FUN_NAME '(' argumentList? ')' ';' //对象方式调用函数，比如lb_1.  zd_1. 等。
	//;
multiCallFun : ('.' VARNAME '(' argumentList? ')') ;
//fun_type:VAR_TYPE
//	| PACK_NAME
//	;


//如果是 := 则自动创建变量。
fun_ret : ret_id (',' ret_id)* FUN_RET_AUTO_DEF? '=' ;

FUN_RET_AUTO_DEF : ':' ;

ret_id : pinvar 
	| '_'
	;

// 定义函数调用的参数列表
argumentList : argument (',' argument)* ;

//单个参数的传递。先这样写，后续可能要加入函数也可做参数
argument : rightvar
	//| CUSTOM_FUN_NAME //匹配函数
	//| CALL_FUN //回调函数，可以直接接收回调函数，继续做参数。
	//| memberFunAccess 	//成员函数都可以做函数的参数，暂不支持，而且可以变现实现。
	;

//if

if : IF_KEY  expr statement zif* qt? ;

zif : ZIF_KEY  expr  statement ;

qt : QT_KEY statement ;

IF_KEY : 'sf' | 'if';

ZIF_KEY : 'zsf' | 'elif';

QT_KEY: 'qt' | 'else';

//for 语句

for : FOR_KEY '(' forinit expr ';' forinc? ')' statement #forState
	| 'while' expr statement #whileState
	| FOR_KEY forinvar ',' forinvar 'in' rightvar statement #forInState
	| FOR_KEY VARNAME ',' VARNAME ',' VARNAME 'in' 'wj.walk' '(' expr (',' expr)* ')' block #forwalk
	;

FOR_KEY: 'xun' | 'for';

forinvar : VARNAME
	| '_'
	;

forinit: defvar
	| assign
	| ';'
	;


//forinc还是先不要和赋值完全混淆在一起。后续还可以+= -= 这些都是表达式。
forinc: pinAutoAddSub
	| assginNoEnd
	| forinc (',' forinc)
	;

break : 'tuichu' | 'break' ';' ;
continue : 'jixu' | 'continue' ';' ;

struct_body : '{' struct_var* '}' ;

struct_var: TYPE_ID VARNAME ';' ;



//结构体
//STRUCT_ID : 'jg'ID ;

//列表
//LIST_ID :  'lb'ID;

//字典
//MAP_ID :  'zd'ID;

//索引
//POINT:	'sy_'ID;

//注意：优先级 TYPE_ID > PACK_NAME > VARNAME
TYPE_ID : 'zs'
	| 'czs'
	| 'xs'
	| 'zfc'
	| 'zf'
	| 'bl'
	| 'wj'
	| 'sj'
	| 'lb'
	| 'zd'
	| 'excel'
	| 'string' //对应QString
	| 'kzf'    //对应QCHAR
	;


BOOL_VALUE : 'zhen' 
	| 'jia'
	| 'true'
	| 'false'
		;

PACK_NAME: 'pin' 
	| 'ndd'
; //包名，现在只有这个。后续可以增加其他。可以给这个包名，增加一个单独的文件，让其从包名中去加载其它文件。

pinFlag : PIN_STATIC_FLAG;

//变量名称


PIN_STATIC_FLAG : 'Pin::UTF16-LE'
	| 'Pin::UTF16-BE'
	| 'Pin::UTF-8'
	| 'Pin::UTF8'
	| 'Pin::GB18030'
	| 'Pin::GBK'
	| 'Pin::EUC-JP'
	| 'Pin::Shift-JIS'
	| 'Pin::EUC-KR'
	| 'Pin::KOI8-R'
	| 'Pin::TSCII'
	| 'Pin::TIS-620'
	| 'Pin::Big5'
	| 'Pin::IBM866'

	| 'Pin::line'
	| 'Pin::fun'

	| 'Pin::CaseSens'
	| 'Pin::NoCaseSens'
	| 'Pin::Base64Encode'
	| 'Pin::Base64UrlEncode'
	| 'Pin::KeepTrailingEquals'
	| 'Pin::OmitTrailingEquals'
	| 'Pin::IgnoreDecodeErrors'
	| 'Pin::AbortOnDecodeErrors'

	//| 'Dirs'
	| 'Pin::AllDirs'
	| 'Pin::Files'
	//| 'Drivers'
	| 'Pin::NoFilter'
	| 'Pin::NoSymLinks'
	| 'Pin::NoDotAndDotDot'
	| 'Pin::Readable'
	| 'Pin::Writable'
	| 'Pin::Executable'
	| 'Pin::Modified'
	| 'Pin::Hidden'
	| 'Pin::System'
	| 'Pin::BottomUp'

	| 'Pin::Name'
	| 'Pin::Time'
	| 'Pin::Size'
	| 'Pin::Type'
	| 'Pin::DirsFirst'
	| 'Pin::DirsLast'
	| 'Pin::IgnoreCase'
	| 'Pin::Reversed'

	| 'Reg::NoPattern'
	| 'Reg::CaseInsensitive'
	| 'Reg::DotMatchesEverything'
	| 'Reg::Multiline'
	| 'Reg::ExtendedPatternSyntax'
	| 'Reg::InvertedGreediness'
	| 'Reg::DontCapture'
	| 'Reg::UseUnicodeProperties'
	;

U16STRING_FLAG: 'u16';

VARNAME : [a-zA-Z_][a-zA-Z0-9_]*;

//文件
//FILE_ID:  'wj_'ID;

//时间

//DATA_TYPE_ID : 'sj';
//DATE_ID: 'sj_'ID;

//整数 zs_ 以zs_ 开头，区分正数和负数
//INT32 : 'zs_'ID ;

//长整数 czs_ 以czs_ 开头，区分正数和负数
//INT64 : 'czs_'ID ;

//小数 xs_ 开头
//FLOAT : 'xs_'ID ;

//长小数 cxs_ 开头
//DOUBLE : 'cxs_'ID ;

//定义字符串
//STRING : 'zfc_'ID ; //字符串

//字符
//CHAR : 'zf_'ID; //单个字符。

//定义bool变量
//BOOL : 'bl'ID; 





//整数值
INT_VALUE : ('0x'|'0X')[0-9A-Fa-f]+ //避免和CHAR_VALUE 冲突，同时让char可以转int
	|'0'
    | [1-9]DIGIT*
    ;

//小数值，只能是0.x 或1.x 形式
FLOAT_VALUE : [1-9]DIGIT* '.' DIGIT* 
    | '0.' DIGIT+
    ;

CHAR_VALUE : '\'' ('\\')?. '\'' 
		//| '\'' ('0x'|'0X') [0-9A-Fa-f][0-9A-Fa-f]? '\''
		;

STRING_VALUE : U16STRING_FLAG? '"' (~["\\\r\n\b]|'\\'.)* '"' 
	|	U16STRING_FLAG? '\'' (~['\\\r\n\b]|'\\'.)* '\'' 
	;  //字符串，来自豆包，回车换行等，必须要通过\进行转义，比如\r\n。不能有单独的" \ 换行,必须转义 
//C 语言中\t 制表符 \r 回车符 \v 垂直制表符 \a响玲 \b 退格符 \f 换页符 \\ 反斜杠符。除了\t外，其余几个都不能直接出现在文本中，必须要使用\转义。 发现\a\v\f好像没有，或者说antlr4不支持，暂时不要。\f可支持，但是打印乱码。

RAW_STRING_VALUE : 'R"('.*?')"' //原始字符串，和cpp11中保存一致，中间xxx可以多行，\r\n不需要转义 .是包含换行的。
	|  'r"' (~["])* '"' 
	|  'r\'' (~['])* '\'' 
	;


//空，对应nullptr 
//NULL : 'kong' ;

//NING : 'ning' ;

//FUN_NAME : 'hs_'ID;	

// 自定义函数名，必须以 hs_ 开头
//CUSTOM_FUN_NAME : 'hs'ID;

//回调函数
//CALL_FUN : 'hd'ID; //必须放在OBJ_FUN_NAME的前面，否则会被优先级拦截

// 对象调用的函数名，可以不以 hs_ 开头
//OBJ_FUN_NAME : VARNAME ;//[a-zA-Z]ID;


//NL: '\r'? '\n' -> channel(HIDDEN);  // 触发行号递增

WS: [ \t\r\n]+ -> channel(HIDDEN); //skip;  //忽略换行。
//WS: [ \t\r\n]+ -> skip;

//WS:[ \t]+;

// 多行注释规则
//LINE_COMMENT : '//' .*? '\r'? '\n' -> channel(HIDDEN);//-> skip;
LINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN); // 单行注释（不含换行符）

COMMENT :'/*' .*? '*/' -> channel(HIDDEN);//->skip ;


/*
VAR_TYPE: //INT32
	 //INT64
	 //FLOAT
	 //STRING
	 STRUCT_ID
	| LIST_ID
	| MAP_ID
	| FILE_ID
	| DATE_ID
	;
	*/



//CPP_FUN_NAME : [A-Za-z]ID; 不能开启，会导致语法无法识别，估计是优先级有些问题。

CHINESE_SYMBOL : [\u3000-\u303F\uFF00-\uFFEF]+; //把中文字符识别出来，在程序监听阶段就做出报错。目前看没有生效。

unknown : .+?;// 原本想打印出一行的，但是\r\n已经在上面被过滤掉了。

fragment

//以字母/以字母或数字结尾的内容，才能是ID
ID	: [a-zA-Z_0-9]+ ;

STKEY : [A-Z_0-9]+ ; //这个一定要放在ID的下面，否则会拦截ID

DIGIT : [0-9] ;

//ChineseSymbol: [\u3000-\u303F\uFF00-\uFFEF];
